OstreeGpgVerifier: Take the signature as a GBytes
authorMatthew Barnes <mbarnes@redhat.com>
Tue, 3 Mar 2015 19:15:27 +0000 (14:15 -0500)
committerMatthew Barnes <mbarnes@redhat.com>
Fri, 6 Mar 2015 13:22:44 +0000 (08:22 -0500)
The signature data is in memory to begin with, so there's no need to
write it to disk only to immediately read it back.

Also, because the GPGME multi-keyring workaround is somewhat expensive
to setup and teardown, concatenate all signatures into a single GBytes
so _ostree_gpg_verifier_check_signature() is only called once.  We're
currently only looking for one valid signature anyway.

src/libostree/ostree-gpg-verifier.c
src/libostree/ostree-gpg-verifier.h
src/libostree/ostree-repo.c

index c5bd911235951a7342a8de4a2b0c100e074913ca..da3601175b19c6c0a54aae4620907e5bb890b457 100644 (file)
@@ -244,7 +244,7 @@ out:
 gboolean
 _ostree_gpg_verifier_check_signature (OstreeGpgVerifier  *self,
                                       GFile              *file,
-                                      GFile              *signature,
+                                      GBytes             *signatures,
                                       gboolean           *out_had_valid_sig,
                                       GCancellable       *cancellable,
                                       GError            **error)
@@ -306,17 +306,16 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier  *self,
       }
   }
 
-  {
-    gs_free char *path = g_file_get_path (signature);
-    gpg_error = gpgme_data_new_from_file (&signature_buffer, path, 1);
-
-    if (gpg_error != GPG_ERR_NO_ERROR)
-      {
-        gpg_error_to_gio_error (gpg_error, error);
-        g_prefix_error (error, "Unable to read signature: ");
-        goto out;
-      }
-  }
+  gpg_error = gpgme_data_new_from_mem (&signature_buffer,
+                                       g_bytes_get_data (signatures, NULL),
+                                       g_bytes_get_size (signatures),
+                                       0 /* do not copy */);
+  if (gpg_error != GPG_ERR_NO_ERROR)
+    {
+      gpg_error_to_gio_error (gpg_error, error);
+      g_prefix_error (error, "Unable to read signature: ");
+      goto out;
+    }
 
   gpg_error = gpgme_op_verify (gpg_ctx, signature_buffer, data_buffer, NULL);
   if (gpg_error != GPG_ERR_NO_ERROR)
index fa718ee96d1e80c958f85e0294cf243fc61ef295..d3a99943b7f80e97ea4e785e4118d3d7808df395 100644 (file)
@@ -43,7 +43,7 @@ OstreeGpgVerifier *_ostree_gpg_verifier_new (GCancellable   *cancellable,
 
 gboolean      _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
                                                     GFile             *file,
-                                                    GFile             *signature,
+                                                    GBytes            *signatures,
                                                     gboolean          *had_valid_signature,
                                                     GCancellable      *cancellable,
                                                     GError           **error);
index 558d008ccd126b3bca5e5bb0a8c1fab7cd6fdb87..b114b02dee4f520db7f2103ec0aa960fc0ca7b97 100644 (file)
@@ -3208,7 +3208,10 @@ _ostree_repo_gpg_verify_file_with_metadata (OstreeRepo          *self,
   gboolean ret = FALSE;
   gs_unref_object OstreeGpgVerifier *verifier = NULL;
   gs_unref_variant GVariant *signaturedata = NULL;
-  gint i, n;
+  GByteArray *buffer;
+  GVariantIter iter;
+  GVariant *child;
+  g_autoptr (GBytes) signatures = NULL;
   gboolean had_valid_signataure = FALSE;
 
   verifier = _ostree_gpg_verifier_new (cancellable, error);
@@ -3239,38 +3242,32 @@ _ostree_repo_gpg_verify_file_with_metadata (OstreeRepo          *self,
       goto out;
     }
 
-  n = g_variant_n_children (signaturedata);
-  for (i = 0; i < n; i++)
-    {
-      GVariant *signature_variant = g_variant_get_child_value (signaturedata, i);
-      gs_unref_object GFile *temp_sig_path = NULL;
-
-      if (!gs_file_open_in_tmpdir (self->tmp_dir, 0644,
-                                   &temp_sig_path, NULL,
-                                   cancellable, error))
-        goto out;
-
-      if (!g_file_replace_contents (temp_sig_path,
-                                    (char*)g_variant_get_data (signature_variant),
-                                    g_variant_get_size (signature_variant),
-                                    NULL, FALSE, 0, NULL,
-                                    cancellable, error))
-        goto out;
+  /* OpenPGP data is organized into binary records called packets.  RFC 4880
+   * defines a packet as a chunk of data that has a tag specifying its meaning,
+   * and consists of a packet header followed by a packet body.  Each packet
+   * encodes its own length, and so packets can be concatenated to construct
+   * OpenPGP messages, keyrings, or in this case, detached signatures.
+   *
+   * Each binary blob in the GVariant list is a complete signature packet, so
+   * we can concatenate them together to verify all the signatures at once. */
+  buffer = g_byte_array_new ();
+  g_variant_iter_init (&iter, signaturedata);
+  while ((child = g_variant_iter_next_value (&iter)) != NULL)
+    {
+      g_byte_array_append (buffer,
+                           g_variant_get_data (child),
+                           g_variant_get_size (child));
+      g_variant_unref (child);
+    }
+  signatures = g_byte_array_free_to_bytes (buffer);
+
+  if (!_ostree_gpg_verifier_check_signature (verifier,
+                                             path,
+                                             signatures,
+                                             &had_valid_signataure,
+                                             cancellable, error))
+    goto out;
 
-      if (!_ostree_gpg_verifier_check_signature (verifier,
-                                                 path,
-                                                 temp_sig_path,
-                                                 &had_valid_signataure,
-                                                 cancellable, error))
-        {
-          (void) gs_file_unlink (temp_sig_path, NULL, NULL);
-          goto out;
-        }
-      (void) gs_file_unlink (temp_sig_path, NULL, NULL);
-      if (had_valid_signataure)
-        break;
-    }
-  
   if (!had_valid_signataure)
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,